package com.longge.websocket.configuration;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
import org.apache.zookeeper.CreateMode;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

import com.longge.common.annotation.EnableZkCurator;
import com.longge.common.configuration.ZkCuratorAutoConfiguration;
import com.longge.common.configuration.ZkCuratorAutoConfiguration.CuratorConfig;
import com.longge.common.util.NetworkUtils;
import com.longge.common.util.ZkUtils;
import com.longge.websocket.util.ServerNodeUtils;

import lombok.extern.slf4j.Slf4j;

@Configuration
@EnableZkCurator
@AutoConfigureAfter(value = {ZkCuratorAutoConfiguration.class})
@Slf4j
public class WebSocketConfiguration {
	@Value("${server.port}")
	private String port;
	
	/**
	 * 此类自动扫描处理@ServerEndpoint的类
	 * @return
	 * @throws Exception 
	 */
	@Bean
    public ServerEndpointExporter serverEndpointExporter() throws Exception {
        return new ServerEndpointExporter();
    }
	
	/**
	 * 注册ZK信息
	 * @return
	 */
	@Bean
	@ConditionalOnBean(value = {CuratorConfig.class})
	public InitServerNode initServerNode() {
		initZkServerNode();
		return null;
	}
	
	static class InitServerNode {
	}
	
	/**
	 * 向ZK注册当前服务节点
	 */
	private void initZkServerNode() {
		String host = NetworkUtils.getDefaultIpV4() + ":" + port;;
		String nodePath = "/"+host;
		try {
			if(!ZkUtils.checkExists(nodePath)) {
				ZkUtils.addNode(nodePath, host.getBytes(), CreateMode.EPHEMERAL);
				log.info("connect zk success");
			}
			ServerNodeUtils.setCurrentNodeHost(host);
			listenChild("/");
			log.info("add zk listener success");
		} catch (Exception e) {
			log.error("create server node error", e);
			throw new RuntimeException(e);
		}
	}
	
	/**
	 * 监听节点变化
	 */
	private void listenChild(String parentPath) {
		/**
		 * children node listener
		 */
		ZkUtils.addChildrenListener(parentPath, new PathChildrenCacheListener() {
			@Override
			public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
				if (event.getType().equals(PathChildrenCacheEvent.Type.CHILD_ADDED)) {
					log.info("child node add event, path:{}", event.getData().getPath());
					ServerNodeUtils.addServer(event.getData().getPath());
				} else if (event.getType().equals(PathChildrenCacheEvent.Type.CHILD_REMOVED)) {
					log.info("child node delete event, path:{}", event.getData().getPath());
					ServerNodeUtils.deleteServer(event.getData().getPath());
				}
			}
		});
	}
}
